#include "gameDesign.h"
#include <string.h>
extern int scancode;
void updateTopFrame(char* video_base){
	char conquered[255],tmp[255];
	strcpy(conquered,"Percentagem conquistada: ");
	float pconq = conqueredArea*100/(float)totalArea;
	sprintf(tmp,"%.2f",pconq);
	strcat(conquered,tmp);
	strcat(conquered," %");
	draw_string(conquered,0,0, WHITE, BLACK, video_base);
	
	char objectivo[255];
	strcpy(objectivo,"objectivo :");
	sprintf(tmp,"%.2f",winPercentage*100);
	strcat(objectivo,tmp);
	strcat(objectivo," %");
	draw_string(objectivo,300,0, RED, BLACK, video_base);
	
	char vidas[255];
	strcpy(vidas,"Vidas :");
	sprintf(tmp,"%d",lives);
	strcat(vidas,tmp);
	draw_string(vidas,500,0, RED, BLACK, video_base);
	
	char pont[255];
	strcpy(pont,"Score :");
	sprintf(tmp,"%d",tempo_pont);
	strcat(pont,tmp);
	draw_string(pont,600,0, WHITE, BLACK, video_base);
	
}
void initializeGameArea(int level,char * video_base){
	
	//draw the initial frame
	clear_screen(BLACK,video_base);
	drawFrame(video_base,frameThickness,0,TopFrame);
	if (level==0)
		gameMat = (int **) malloc((VRES/enemyYDiameter)*sizeof(int*));
	int numVerticalLines = frameThickness/enemyXDiameter+1;
	int numHorizontalLines= frameThickness/enemyYDiameter+1;
	int i = 0;
	totalArea=0;
	for(i = 0; i< VRES/enemyYDiameter;i++){
		if(level==0)
			gameMat[i] = (int*) malloc((HRES/enemyXDiameter)*sizeof(int));
		
		int j = 0;
		for(j = 0; j< HRES/enemyXDiameter;j++){
			gameMat[i][j]=unconqueredPosition;
			totalArea++;
		}
	}

	for(i=0;i<HRES/enemyXDiameter;i++){
		int j;
		for(j= 0;j<numHorizontalLines;j++){
			gameMat[TopFrame/enemyYDiameter+j][i]=conqueredPosition;
			gameMat[VRES/enemyYDiameter-1-j][i]=conqueredPosition;
		}
		gameMat[VRES/enemyYDiameter-1-j][i]=conqueredPosition;
	}
	for(i=TopFrame/enemyYDiameter;i<VRES/enemyYDiameter;i++){
		int j;
		for(j= 0;j<numVerticalLines;j++){
			gameMat[i][0+j]=conqueredPosition;
			gameMat[i][HRES/enemyXDiameter-1-j]=conqueredPosition;
			}
			gameMat[i][HRES/enemyXDiameter-1-j]=conqueredPosition;
	}
		
	if(level>0){
		for(i=0; i < enemyNumber; i++)
			destroy_sprite(enemySprite[i], video_base);
		free(enemySprite);
	}
	enemyNumber = 2	+ level;
	winPercentage=((level+1)*(level+1)*(level+1)/300.0 +60.0)/100.0;
	enemySprite = (Sprite **)malloc(enemyNumber * sizeof(Sprite*));
	playerSprite = create_sprite(playerBall,video_base,0,30);
	
	playerSprite->xspeed = 5;
	playerSprite->yspeed = 5;
	for(i=0; i < enemyNumber; i++){
		enemySprite[i] = create_sprite(enemyBall,video_base, randBetween(frameThickness+1,HRES-frameThickness-10), randBetween(frameThickness+31, VRES-frameThickness-10));
		enemySprite[i]->xspeed = level +1;
		enemySprite[i]->yspeed = level+1;
		}
	
}

void moveEnemy(char * video_base)
{	
	int i = 0;
	while (i<enemyNumber){
		erase_sprite(enemySprite[i], video_base,BLACK);
		gameMat[(enemySprite[i]->y)/enemyYDiameter][enemySprite[i]->x/enemyXDiameter]=unconqueredPosition;
	
		if( gameMat[(enemySprite[i]->y)/enemyYDiameter][(enemySprite[i]->x+enemySprite[i]->xspeed *enemySprite[i]->xdirection)/enemyXDiameter]==unconqueredPosition )
			enemySprite[i]->x+=enemySprite[i]->xspeed *enemySprite[i]->xdirection;
		else if ( gameMat[(enemySprite[i]->y)/enemyYDiameter][(enemySprite[i]->x+enemySprite[i]->xspeed *enemySprite[i]->xdirection)/enemyXDiameter]==playerTrail ){
				gState=PlayerCrashed;
				return;
			}else
				enemySprite[i]->xdirection *= -1;
			
		if( gameMat[(enemySprite[i]->y+enemySprite[i]->yspeed*enemySprite[i]->ydirection)/enemyYDiameter][(enemySprite[i]->x)/enemyXDiameter]==unconqueredPosition)
			enemySprite[i]->y+=enemySprite[i]->yspeed*enemySprite[i]->ydirection;
		else if ( gameMat[(enemySprite[i]->y+enemySprite[i]->yspeed*enemySprite[i]->ydirection)/enemyYDiameter][(enemySprite[i]->x)/enemyXDiameter]==playerTrail)
			{
				gState=PlayerCrashed;
				return;
			}else
				enemySprite[i]->ydirection*=-1;
			
			
		//printf("%d\r",gameMat[(enemySprite[i]->y)/enemyYDiameter][(enemySprite[i]->x)/enemyXDiameter]);
		
			
		gameMat[(enemySprite[i]->y)/enemyYDiameter][enemySprite[i]->x/enemyXDiameter]=enemyBallPosition;
		draw_sprite(enemySprite[i],video_base);
		
		
		i++;
		
		}
		
}
void removeTrail(int color,char* video_base){
	int i;
	int j;
	for(i=0;i<VRES;i++)
		for(j=0;j<HRES;j++)
			if(get_pixel(j,i,video_base)==TrailColor)
				set_pixel(j,i,color,video_base);
//	drawFrame(video_base,frameThickness,0,TopFrame);
	
}
void getFirstTrail(int * x, int*y,char * video_base){

	int xmax = 0,ymax=0;
	int xmin = HRES+10,ymin=VRES+10;
	for(*y=0;*y<VRES/(enemyYDiameter);(*y)++)
		for(*x=0;*x<HRES/enemyXDiameter;(*x)++){
			if(gameMat[*y][*x]==playerTrail){
				if(*x>=xmax){
					xmax=*x;
					ymax=*y;
					//put_int_at(ymax,enemyXDiameter*xmax+20,enemyYDiameter*ymax+50,RED,BLACK,video_base);
					//int k=0;
					//while(k<99999)k++;
				}	
				
				if(*x<xmin){
					xmin=*x;
					ymin=*y;
				}
			gameMat[*y][*x]=conqueredPosition;
	//		conqueredArea++;
			
			}
		}
	
	*x=xmax-1;
	*y=ymax-1;
//	gameMat[*y][*x]=conqueredPosition;
}
int getNumConquered(){
	int i;
	int j;
	int count = 0;
	for(i = 1; i< VRES/enemyYDiameter;i++)
		for(j = 1; j< HRES/enemyXDiameter;j++)
			if(gameMat[i][j]==conqueredPosition)
				count++;
		
	return count;
}
void fillArea(char * video_base)
{
	int y=1,x=1;
	getFirstTrail(&x,&y,video_base);
	x*=enemyXDiameter;
	y*=enemyYDiameter;
		//printGameMatrix();
	removeTrail(ConqueredColor,video_base);
	stackT stack;
	StackInit(&stack,HRES*VRES);
	Point p;
	p.x=x;
	p.y=y;
	StackPush(&stack,p);
	do{
		
		p=StackPop(&stack);
		int x_right=p.x,x_left=p.x;
		int y=p.y;
		int pixel = get_pixel(x_right,y,video_base);

		while(pixel!=ConqueredColor && pixel!=TrailColor ){	
			set_pixel(x_right,y,ConqueredColor,video_base);
			gameMat[y/enemyYDiameter][x_right/enemyXDiameter]=conqueredPosition;
			//conqueredArea++;
			x_right++;
			pixel = get_pixel(x_right,y,video_base);
		}
		pixel = get_pixel(x_left-1,y,video_base);
	
		while(pixel!=ConqueredColor && pixel!=TrailColor ){	
			set_pixel(x_left,y,ConqueredColor,video_base);
			gameMat[y/enemyYDiameter][x_left/enemyXDiameter]=conqueredPosition;
			//conqueredArea++;
			x_left--;
			pixel = get_pixel(x_left,y,video_base);
		}
		int x_left2 = x_left;
		int pixelUp=get_pixel(x_left,y-1,video_base);
		for(;x_left<x_right && pixelUp==ConqueredColor ;x_left++)
			pixelUp=get_pixel(x_left,y-1,video_base);
	
		if(pixelUp!=ConqueredColor){
			Point p1;
			p1.x=x_left-1;
			p1.y=y-1;
			StackPush(&stack,p1);
			int px;
			do{
				px = get_pixel(p1.x,p1.y,video_base);
				p1.x++;
			}while(p1.x<x_right && px==BLACK);
			StackPush(&stack,p1);
		}
		int pixelDown=get_pixel(x_left2,y+1,video_base);
		for(;x_left2<x_right && pixelDown==ConqueredColor ;x_left2++)
			pixelDown=get_pixel(x_left2,y+1,video_base);
		if(pixelDown!=ConqueredColor){
			Point p1;
			p1.x=x_left2-1;
			p1.y=y+1;
			StackPush(&stack,p1);
			int px;
			do{
				px = get_pixel(p1.x,p1.y,video_base);
				p1.x++;
			}while(p1.x<x_right && px==BLACK);
			StackPush(&stack,p1);
		}  
	}while(!StackIsEmpty(&stack));
	StackDestroy(&stack);
	conqueredArea = getNumConquered(); 
	updateTopFrame(video_base);
	if (conqueredArea>totalArea*winPercentage){
		gState = Waiting;
		waitState=NextLevel;
		tempo_aux=1000;
	}
	isOut=0;
			
}
void movePlayerUp(char * video_base){

	int nextPos = (playerSprite->y-playerSprite->yspeed) > enemyYDiameter+TopFrame ? playerSprite->y-playerSprite->yspeed:enemyYDiameter+TopFrame; 
	int	nextColor = isOut ? TrailColor:ConqueredColor;
	for(;playerSprite->y>nextPos;){
		switch (gameMat[(playerSprite->y)/enemyYDiameter-1][playerSprite->x/enemyXDiameter]){
			case playerTrail:
			case enemyBallPosition:
					gState=PlayerCrashed;
					return;
			case conqueredPosition:
					if(isOut){
						int i;
						for(i=0;i<enemyYDiameter*3;i++){
						erase_sprite(playerSprite,video_base,playerSprite->y>frameThickness ? TrailColor:ConqueredColor);		
						if(playerSprite->y>TopFrame+1)
							playerSprite->y--;
						draw_sprite(playerSprite,video_base);
						//gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;
						}
						fillArea(video_base);
						isOut=0;
					}
					break;
			case unconqueredPosition:
					isOut=1;					
					gameMat[(playerSprite->y-1)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;
					break;
			}
		erase_sprite(playerSprite,video_base,nextColor);		
		playerSprite->y--;
		draw_sprite(playerSprite,video_base);
	
		}
}
void movePlayerDown(char * video_base){

	int nextPos = (playerSprite->y+playerSprite->yspeed) < VRES-enemyYDiameter ? playerSprite->y+playerSprite->yspeed:VRES-enemyYDiameter; 
	int	nextColor = isOut ? TrailColor:ConqueredColor;
	for(;playerSprite->y<nextPos;){
		switch (gameMat[(playerSprite->y)/enemyYDiameter+1][playerSprite->x/enemyXDiameter]){
			case playerTrail:
			case enemyBallPosition:
				gState=PlayerCrashed;
				return;
			case conqueredPosition:
				if(isOut){
						int i;
						for(i=0;i<enemyYDiameter*3;i++){
						erase_sprite(playerSprite,video_base,WHITE);		
						if(playerSprite->y<VRES)
							playerSprite->y++;
						draw_sprite(playerSprite,video_base);
						//gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;
						}
						fillArea(video_base);
						isOut=0;
					}
			
				break;
			case unconqueredPosition:
				isOut=1;
				gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;
				break;
			}
			erase_sprite(playerSprite,video_base,nextColor);	
			playerSprite->y++;
			draw_sprite(playerSprite,video_base);
	}	
}
void movePlayerLeft(char * video_base)
{
	int nextPos = playerSprite->x-playerSprite->xspeed > 0 ? playerSprite->x-playerSprite->xspeed : 0;
	int	nextColor = isOut ? TrailColor:ConqueredColor;
	for(;playerSprite->x>nextPos;){
		switch (gameMat[(playerSprite->y)/enemyYDiameter][(playerSprite->x)/enemyXDiameter-1]){
			case playerTrail:
			case enemyBallPosition:
				gState=PlayerCrashed;
				return;
			case conqueredPosition:
					if(isOut){
						int i;
						for(i=0;i<enemyXDiameter*3;i++){
						erase_sprite(playerSprite,video_base,WHITE);		
						if(playerSprite->x>0)
							playerSprite->x--;
						draw_sprite(playerSprite,video_base);
						//gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;
						}
						fillArea(video_base);
						isOut=0;
					}
					break;
			case unconqueredPosition:
					isOut=1;
					gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;	
					break;
				}
		erase_sprite(playerSprite,video_base,nextColor);
		playerSprite->x--;
		draw_sprite(playerSprite,video_base);
		}
}
void movePlayerRight(char * video_base)
{
	int nextPos = playerSprite->x+playerSprite->xspeed < HRES-enemyXDiameter ? playerSprite->x+playerSprite->xspeed : HRES-enemyXDiameter;
	int	nextColor = isOut==1 ? TrailColor:ConqueredColor;
	for(;playerSprite->x<nextPos;){
		switch (gameMat[(playerSprite->y)/enemyYDiameter][(playerSprite->x)/enemyXDiameter+1]){
			case playerTrail:
			case enemyBallPosition:
					gState=PlayerCrashed;
					return;
			case conqueredPosition:
					if(isOut){
						int i;
						for(i=0;i<enemyXDiameter*3;i++){
						erase_sprite(playerSprite,video_base,WHITE);		
						if(playerSprite->x<HRES-enemyXDiameter/2)
							playerSprite->x++;
						draw_sprite(playerSprite,video_base);
						//gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;
						}
						fillArea(video_base);
						isOut=0;
					}
				
					break;
			case unconqueredPosition:
					isOut=1;
					gameMat[(playerSprite->y)/enemyYDiameter][playerSprite->x/enemyXDiameter]=playerTrail;					
					break;							
		}
		erase_sprite(playerSprite,video_base,nextColor);
		playerSprite->x++;
		draw_sprite(playerSprite,video_base);
	}
}


void movePlayer(int d,char * video_base){

	switch(d){
		case UP: movePlayerUp(video_base);
				 break;	
		case DOWN:movePlayerDown(video_base);
				break;
					
		case LEFT:movePlayerLeft(video_base);
				break;
			
		case RIGHT:movePlayerRight(video_base);
				break;
		return;
	}
}

void gameControl(char * video_base){
	int last_sc =0;
	do
	{	
		//printf("%d\r",gState);
		switch(gState){
			case Menu:
				return;
			case Begin:
				tempo_pont=0;
				level = 0;
				gState=BeginLevel;
				lives = 3;
				break;
			case BeginLevel:
				isOut=0;
				initializeGameArea(level, video_base);
				conqueredArea = 0;
				gState=Playing;
				printGameMatrix();
				updateTopFrame(video_base);
				break;
			case Playing:
				
					last_sc = scancode;
					switch(last_sc){
							case UpKey: gState=PlayerMoving;
										movePlayerUp(video_base);
										break;
							case DownKey: gState=PlayerMoving;
										movePlayerDown(video_base);
										break;
							case LeftKey: gState=PlayerMoving;
										movePlayerLeft(video_base);
										break;
							case RightKey: gState=PlayerMoving;
										movePlayerRight(video_base);
										break;		
							default:break;
					}
				
			
				
				if(gState != PlayerCrashed && waitState != NextLevel){
						tempo_aux = 20;
					gState = Waiting;
					waitState=Playing;
				}
				moveEnemy(video_base);
				
				break;

			case Waiting: 
				if(tempo_aux<=0)
					gState=waitState;
				
					break;
			case PlayerCrashed:
					if (lives>0){
						lives--;
						restartPosition(video_base);
						
					}else{						
						draw_string("You just LOST THE GAME",HRES/2-15*4, 140, WHITE, BLACK, video_base);
						tempo_aux=1000;
						gState=Waiting;
						waitState=End;
					}
					gState = Waiting;
				break;
			
			case NextLevel:
				level++;	
				gState=Waiting;
				waitState=BeginLevel;
				tempo_aux=1000;
				char msg[255];
				char tmp[255];
				strcpy(msg,"Nivel ");
				itoa(level+1,tmp,10);
				strcat(msg,tmp);
				clear_screen(BLACK,video_base);
				draw_string(msg,HRES/2-15*4, 140, RED, BLACK, video_base);
				break;
			case End :printGameMatrix();
					isOut=0;
					checkHighScore(video_base);
					break;
						
					
			
			default : break;
			}
		
	} while(last_sc != 0x1);		
}

void restartPosition(char * video_base){
	int i;
	int j;
	for(i = 0; i< VRES/enemyYDiameter;i++)
		for(j = 0; j< HRES/enemyXDiameter;j++)
			if(gameMat[i][j]==playerTrail){
			
				gameMat[i][j]=unconqueredPosition;
				
			}
	int numVerticalLines = frameThickness/enemyXDiameter+1;
	int numHorizontalLines= frameThickness/enemyYDiameter+1;
	for(i=0;i<HRES/enemyXDiameter;i++){
		int j;
		for(j= 0;j<numHorizontalLines;j++){
			gameMat[TopFrame/enemyYDiameter+j][i]=conqueredPosition;
			gameMat[VRES/enemyYDiameter-1-j][i]=conqueredPosition;
		}
		gameMat[VRES/enemyYDiameter-1-j][i]=conqueredPosition;
	}
	for(i=TopFrame/enemyYDiameter;i<VRES/enemyYDiameter;i++){
		int j;
		for(j= 0;j<numVerticalLines;j++){
			gameMat[i][0+j]=conqueredPosition;
			gameMat[i][HRES/enemyXDiameter-1-j]=conqueredPosition;
			}
			gameMat[i][HRES/enemyXDiameter-1-j]=conqueredPosition;
	}
			
	erase_sprite(playerSprite,video_base,BLACK);
	playerSprite->x=0;
	playerSprite->y=TopFrame;
	draw_sprite(playerSprite,video_base);
	isOut=0;
	removeTrail(BLACK,video_base);
	updateTopFrame(video_base);
}
void printGameMatrix(){
	FILE* pFile;
	int i;
	pFile = fopen("teste.txt", "w");
	for(i = 0; i< VRES/enemyYDiameter;i++){
		int j = 0;
		for(j = 0; j< HRES/enemyXDiameter;j++)
			fprintf(pFile,"%d",gameMat[i][j]);
		fprintf(pFile,"\n");
	}	
}

Pontuacoes *read_pontuacoes(){
	char line[255];
	Pontuacoes * pontuacao = malloc(11*sizeof(Pontuacoes));
	int pont;
	FILE *file;
	file=fopen("pontuacoes.txt", "r");
	if(file == NULL){
		//printf("file not found\n");
		return NULL;
	}
	else{
		fgets(line, 255, file);
		int n = atoi(line);
		int i = 0;
		for(;i<n;i++){
			fgets(line, 255, file);
			line[strlen(line)-1]='\0';
			//pontuacao[i].nome = malloc (strlen(line));
			strcpy(pontuacao[i].nome, line);
			fgets(line, 255, file);
			pont = atoi(line);
			pontuacao[i].pontua = pont;
		}
		for(;i<10;i++){
		
			strcpy(pontuacao[i].nome,"NULL");
		}
		fclose(file);
	}
	return pontuacao;
}

int isHighScore(Pontuacoes * p){
	int i;
	for(i=0;i<10 && strcmp(p[i].nome,"NULL")!=0;i++)
		if(p[i].pontua<tempo_pont)
			return i;
	if (i<10)
		return i;
	return -1;
	
}
void write_pontuacoes(Pontuacoes pontuacao[]){
	FILE * file;
	file = fopen("pontuacoes.txt", "w");
	int i = 0;
	while (i<10 && strcmp(pontuacao[i].nome, "NULL")!=0) i++;
	int k;
	char tmp[255];
	sprintf(tmp,"%d\n",i);
	fputs(tmp,file);
	for(k=0;k<i;k++)
	{
		strcat(pontuacao[k].nome,"\n");
		fputs(pontuacao[k].nome,file);
		sprintf(tmp,"%d\n",pontuacao[k].pontua);
		fputs(tmp,file);
	
	}
	fclose(file);
}

void checkHighScore(char * video_base){

	Pontuacoes * pontuacao = read_pontuacoes();
	int count=0;
	int indice=-1;
	while(strcmp(pontuacao[count].nome,"NULL")!=0 && count <10) count++;
	indice=isHighScore(pontuacao);
	if(indice!=-1){
		clear_screen(RED,video_base);
		draw_string("Atingiu um high-score", HRES/2-50, 140, BLACK, RED, video_base);
		int k;
		Pontuacoes p;
		strcpy(p.nome,name);
		p.pontua=tempo_pont;
		for(k=0;k<10 && strcmp(pontuacao[k].nome,"NULL")!=0;k++);
		int i;
		for(i=k;i>indice;i--)
			pontuacao[i]=pontuacao[i-1];
		pontuacao[indice]=p;
		write_pontuacoes(pontuacao);	
		gState=Waiting;		
		waitState=Menu;
		tempo_aux=2000;
		}
	}
	

